Eddie's Lessons, version 7

Adding the CodeAChrome Control.

level: any

by Alyce Watson [http://alycesrestaurant.com/]

Home

Wire 1.0

Gif Viewer

Report Generation

Flow Charting

Stylebits Corner

Tip Corner

API Corner

CodeAChrome

Sprite Byte

Control Panel Applets

HTTPS Data

Eddie

Submissions

Index


What is Eddie?

Eddie is a new code editor written in Liberty BASIC, for Liberty BASIC. Eddie can be customized and extended to meet the needs of the individual programmer. The newest version is available here: Eddie!


What is CodeAChrome?

CodeAChrome is a new, FREE code editing component. Some features of CodeAChrome.DLL:

The Bare Minimum CodeAChrome Program!

Because CodeAChrome comes with a built-in menu for file and editing functions, you need to make only two API calls to create a complete code editing program. To create the control, use CreateCodeAChrome. When the program ends, you must destroy the control with DestroyCodeAChrome. That's all you need! Here's a wee demo. The functions will be explained later in this article.

nomainwin
WindowWidth=580:WindowHeight=480
menu #1, "&File", "E&xit", [quit]
    
open "CodeAChrome Editor Demo" for window_nf as #1
#1 "trapclose [quit]"

open "CodeAChrome.dll" for dll as #r
hMain = hwnd(#1)
calldll #r, "CreateCodeAChrome", hMain as long,_
10 as long, 10 as long,550 as long, 400 as long, ret as long

if ret=0 then 
    notice "Error loading CodeAChrome. Program ended."
    goto [quit]
end if
wait

[quit]
    calldll #r, "DestroyCodeAChrome", ret as void
    close #r
    close #1
    end   

Eddie Uses CodeAChrome!

Getting Started with CodeAChrome

Since Eddie will now use CodeAChrome, we can remove the graphicbox for line numbers, the Liberty BASIC texteditor, and the timer command. The timer was used to check for a change in the origin so that the line numbers could be redrawn as needed. CodeAChrome has its own line number feature and texteditor, and it automatically keeps the line numbers in synch with the visible lines in the editor.

CodeAChrome.DLL allows only one CodeAChrome control in a Liberty BASIC program.

To add CodeAChrome, we need the handle of the window, which we obtain with the HWND command. We also must open the DLL and give it a handle. Liberty BASIC lets us call on Windows DLLs like #user32 without opening them, but we must explicitly open other DLLs.

    open "CodeAChrome.dll" for dll as #r
    hMain = hwnd(#1)    'handle of program window

Next, we create the control with CreateCodeAChrome. We'll place it at the left edge of our window, so the left X argument is set to 0. We want to leave room for the buttons and the branch label combobox, so the top Y location is set to 52. The width and the height don't really matter, because we'll activate the resizehandler and resize the control as soon as the window opens. If the function returns 0, the creation of the CodeAChrome control failed and we end the program.

    calldll #r, "CreateCodeAChrome",_   'code editing component
    hMain as long,_     'handle of program window
    0 as long,_         'x location of control 
    52 as long,_        'y location of control
    545 as long,_       'width of control
    250 as long,_       'height of control
    ret as long         'nonzero=success
    
    if ret=0 then 
        notice "Error loading CodeAChrome. Program ended."
        goto [quit]
    end if

Moving and Resizing CodeAChrome

The window will have a sizing frame so that the user can resize it. When we used a Liberty BASIC texteditor and graphicbox, we issued commands that caused them to resize automatically when a window was resized. CodeAChrome does not automatically resize, so we'll set up a handler for the event of resizing:

    #1 "resizehandler [resize]"

For more info on the resizehandler, see Tip Corner.

To move and resize CodeAChrome, use the MoveCodeAChrome function. The arguments required are the new X and Y location and the desired width and height of the control. The function does not return a value.

[resize]    
    ww=WindowWidth : wh=WindowHeight-52
    calldll #r, "MoveCodeAChrome",_ 'move/resize the control
    0 as long,_     'new x location
    52 as long,_    'new y location
    ww as long,_    'new width
    wh as long,_    'new height
    re as void
    #1 "refresh"
    wait

As you can see in the code above, we use the WindowWidth and WindowHeight to calculate the new size for CodeAChrome. These variables are set by Liberty BASIC to contain the client area width and height when the resizehandler is activated. If we activate the resizehandler we don't need to do any extra API calls to get the dimensions of the client area in order to set the size for CodeAChrome. The size of the client area varies from computer to computer, dependent upon the user's display settings.

We can force the resizehandler to be activated right after the window opens by using the MoveWindow API call. For more on this API call, see API Corner. Be sure to use slightly different values than the original WindowWidth and WindowHeight for the new width and height of the window, so that LB recognizes that the window has been resized.

    'activate resizehandler
    calldll #user32, "MoveWindow",_
    hMain as ulong, _   'window handle
    UpperLeftX as long,_    'x location of window
    UpperLeftY as long,_    'y location of window
    730 as long,_           'desired width of window
    590 as long,_           'desired height of window
    1 as boolean, ret as long

Destroying CodeAChrome

It's important to destroy the control before we close the program window. We simply add DestroyCodeAChrome to the [quit] subroutine. The function does not return a value. We must be sure to close the DLL, as well.

[quit]
    gosub [writeIniFile]
    calldll #r, "DestroyCodeAChrome", ret as void
    close #r : close #1 : END

Editing Functions

CodeAChrome has a built-in context menu that includes all of the standard editing functions, plus a find/replace dialog. It is accessed when the user right-clicks on the CodeAChrome control.

Liberty BASIC provides an automatic Edit Menu for the texteditor control. We no longer have that feature in Eddie, so if we want an Edit Menu on the menubar, we must implement it ourselves.

Menu        #1, "&Edit", "&Undo",[undo],"Cu&t",[cut],"&Copy",[copy],"&Paste",[paste],|,_
            "&Select All",[selectall]

CodeAChrome provides several editing functions, which are included in the code below. These functions to not return a value. They are written on two lines for clarity in Eddie, but they can be placed on a single line for conciseness. The editing functions all look like this one:

calldll #r, "EditUndo", re as void

The functions are EditUndo, EditCutText, EditCopyText, EditPasteText, EditSelectAll. As they appear in Eddie:

[undo]
    calldll #r, "EditUndo",_    'undo last operation
    re as void
    wait

[cut]   
    calldll #r, "EditCutText",_ 'cut selected text to clipboard
    re as void
    wait
    
[copy] 
    calldll #r, "EditCopyText",_    'copy selected text to clipboard
    re as void
    wait
    
[paste]    
    calldll #r, "EditPasteText",_   'paste contents of clipboard at cursor
    re as void
    wait
    
[selectall]
    calldll #r, "EditSelectAll",_   'select all text in control
    re as void
    wait

File Functions - New, Open, Save, Print

These functions are included in the automatic right-click context menu, but we can also access them directly. None of the functions returns a value. To remove all contents of the CodeAChrome control, issue a DoNew command:

    calldll #r, "DoNew",_   'clear control
    re as void

To load a file from disk into the CodeAChrome and replace the current contents of the control, issue a FileLoad command. It requires the name of the file on disk, and it does not return a value:

    
    calldll #r, "FileLoad",_    'load file into codeachrome
    openfile$ as ptr,_  'name of file
    re as void          'no return

To save the contents of the CodeAChrome control to disk, use the FileSave function. It requires the desired filename, and it does not return a value.

    calldll #r, "FileSave",_    'save contents to disk
    file$ as ptr,_      'save filename
    re as void

When Eddit attempts to run the current code in Liberty BASIC, it writes the contents of the control to disk with the name "tempfile$". It then uses the RUN command to run tempfile$.

    calldll #r, "FileSave",_    'save contents to disk
    tempfile$ as ptr,_      'save filename
    re as void

    RUN LibertyExe$ + " " + chr$(34) + tempfile$ + chr$(34)

CodeAChrome makes it very easy to print a hard copy of the contents. Use the DoPrint command, which does not return a value.

    calldll #r, "DoPrint",_   'print contents of control
    re as void

Scrolling a Line to the Top

Eddie has a tool that allows a user to specify a line number and scroll that line to the top. To convert to CodeAChrome, keep in mind that the line numbers begin at 0.

We'll first need to retrieve the number of lines in the control with GetNumberOfLines. We won't try to scroll to a line number that is larger than the actual number of lines contained in the control. We then call SetTopLine to scroll the designated line to the top. This is similar to the Liberty BASIC "!origin" command, but it only scrolls the lines of text, not the columns. SetTopLine does not return a value.

[gotoLine]
    calldll #r, "GetNumberOfLines",_
    rowcount as long    'returns number of lines, 0-indexed
    gotoLine=rowcount-1
    msg$="Go to line? Max is ";gotoLine
    prompt msg$;gotoLine
    if gotoLine>rowcount-1 then gotoLine=rowcount
    if gotoLine<0 then gotoLine=0
    
    calldll #r, "SetTopLine",_  'scroll this line to top
    gotoLine as long,_          'index of line
    re as void                  'no return
    wait

Filling the Branch Label Combobox

CodeAChrome has functions to retrieve the length of a line of text, and the text in a line. We'll use those instead of the texteditor "!line" command that we used in previous versions of Eddie. After we retrieve the number of lines, we'll iterate through them in a loop. For each line, we'll retrieve the length of the text so that we can set up the proper size string buffer to hold the text. To do that, we use the GetLineTextLength function, like this:

        calldll #r, "GetLineTextLength",_   'retrieve length of text in line
        i as long,_     'index of line
        length as long  'returns length

We then create a string variable large enough to hold the text.

        line$ = space$(length + 1)  'create buffer to receive text

Then we use GetLineText to get the text into the "line$" variable. This function does not return a value.

        calldll #r, "GetLineText",_
        i as long,_     'index of line to retrieve
        line$ as ptr,_  'buffer for text
        ret as void

After the function returns, the text in the line is in the variable called "line$". We then treat it just as we did in previous versions of Eddie, checking to see if the line contains a branch label, sub, or function definition. If it does, we load it into the combobox, along with the index of the line. Here is the routine that fills the branch label combobox:

[fillBranch]
    calldll #r, "GetNumberOfLines",_
    rowcount as long    'returns number of lines, 0-indexed
    rowcount = rowcount - 1 'because lines begin at 0
    
    REDIM branch$(rowcount)
    branch$(1)=""  + space$(300) + "1"

    'fill combobox with labels, functions and sub definitions
    'pad with 300 spaces, then add line number
    bx=2
    For i=0 to rowcount
        calldll #r, "GetLineTextLength",_   'retrieve length of text in line
        i as long,_     'index of line
        length as long  'returns length
        
        line$ = space$(length + 1)  'create buffer to receive text
        calldll #r, "GetLineText",_
        i as long,_     'index of line to retrieve
        line$ as ptr,_  'buffer for text
        ret as void
        
        If Left$(Trim$(line$),1)="[" Then
            branch$(bx)=Trim$(line$) + space$(300) + str$(i)
            bx=bx+1
        End If
        If Lower$(Word$(line$,1))="function" Then
            branch$(bx)=Trim$(line$) + space$(300) + str$(i)
            bx=bx+1
        End If
        If Lower$(Word$(line$,1))="sub" Then
            branch$(bx)=Trim$(line$) + space$(300) + str$(i)
            bx=bx+1
        End If
    Next 

    #1.c "reload"
    #1.c "selectindex 1";
    return

Scrolling to a Branch Label in the Code

When the user selects a branch label from the combobox, we check the last part of the selected item to extract the line number. (See the previous Eddie installment for more information on this techinique.) We then use the SetTopLine function described earlier in this article to scroll the correct line to the top.

[chooseBranch]
   '** CHOOSE BRANCH, SET EDITOR TO THAT POSITION
    #1.c "selection? branchselect$"
    
    'get the text at the end of the item
    ln$ = right$(branchselect$, 6)
    
    'get value of text, which will = linenumber
    linenumber = val(ln$)
    
    'now scroll texteditor so that line is at top
    calldll #r, "SetTopLine",_  'scroll this line to top
    linenumber as long,_          'index of line
    re as void                  'no return
    Wait

There's More!

Watch for more features of CodeAChrome in future versions of Eddie.


Home

Wire 1.0

Gif Viewer

Report Generation

Flow Charting

Stylebits Corner

Tip Corner

API Corner

CodeAChrome

Sprite Byte

Control Panel Applets

HTTPS Data

Eddie

Submissions

Index